/***************************************************************************
 *   Copyright (C) 2010 by Peter Hatina                                    *
 *   email: phatina (at) gmail.com                                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License           *
 *   version 2.1 as published by the Free Software Foundation              *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Lesser General Public License for more details.                   *
 *   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.               *
 ***************************************************************************/

#include "batterymeter.h"
#include "tabwidgetitem.h"
#include "common.h"

extern "C"
{
#if (defined(Q_OS_LINUX))
#  include <libacpi.h>
#elif (defined(Q_OS_WIN32))
#  include <powrprof.h>
#endif
}

BatteryMeter::BatteryMeter()
{
}

BatteryMeter::~BatteryMeter()
{
}

void BatteryMeter::update()
{
#ifdef Q_OS_LINUX
    global_t global;
    init_acpi_batt(&global);
    init_acpi_acadapt(&global);

    int act_batt = -1;
    if (global.batt_count == 0)
    {
        m_present = false;
        return;
    }
    else
    {
        for (int i = 0; act_batt == -1 && i < global.batt_count; i++)
        {
            if (batteries[i].present)
                act_batt = i;
        }
    }

    //ac adaptor online
    m_ac_online = global.adapt.ac_state == P_AC;

    if (act_batt == -1)
    {
        //no battery detected
        m_present = false;
        return;
    }

    read_acpi_batt(act_batt);

    //charging state
    switch (batteries[act_batt].charge_state)
    {
    case C_CHARGE:
        m_state = CHARGING;
        break;

    case C_DISCHARGE:
        m_state = DISCHARGING;
        break;

    case C_CHARGED:
        m_state = CHARGED;
        break;

    case C_NOINFO:
    case C_ERR:
        m_state = UNKNOWN;
        break;
    }

    m_present = true;
    m_design_capa = batteries[act_batt].design_cap;
    m_remain_capa = batteries[act_batt].remaining_cap;
    m_remain_time = batteries[act_batt].remaining_time;
    m_percentage = batteries[act_batt].percentage;
    m_rate = batteries[act_batt].present_rate;
#endif

#ifdef Q_OS_WIN32
    SYSTEM_BATTERY_STATE batt_state;

    if (CallNtPowerInformation(SystemBatteryState, NULL, 0, static_cast <void *>
                               (&batt_state), sizeof(SYSTEM_BATTERY_STATE)) != STATUS_SUCCESS)
    {
        //TODO prerobit
        m_state = UNKNOWN;
        return;
    }

    double rem_capa = batt_state.RemainingCapacity;
    double max_capa = batt_state.MaxCapacity;

    m_present = batt_state.BatteryPresent;
    m_ac_online = batt_state.AcOnLine;
    m_design_capa = batt_state.MaxCapacity;
    m_remain_capa = batt_state.RemainingCapacity;
    m_remain_time = batt_state.EstimatedTime / 60;
    m_percentage = static_cast <int> (rem_capa / max_capa * 100.0 + 0.5);
    m_rate = static_cast <long> (batt_state.Rate);

    if (batt_state.Charging)
        m_state = CHARGING;
    else if (batt_state.Discharging)
        m_state = DISCHARGING;
    else if (!batt_state.Charging && !batt_state.Discharging)
        m_state = CHARGED;
    else
        m_state = UNKNOWN;
#endif
}

bool BatteryMeter::batteryPresent() const
{
    return m_present;
}

bool BatteryMeter::acOnline() const
{
    return m_ac_online;
}

unsigned long BatteryMeter::designCapa() const
{
    return m_design_capa;
}

unsigned long BatteryMeter::remainCapa() const
{
    return m_remain_capa;
}

unsigned long BatteryMeter::remainTime() const
{
    return m_remain_time;
}

unsigned long BatteryMeter::percentage() const
{
    return m_percentage;
}

long BatteryMeter::rate() const
{
    return m_rate;
}

BatteryMeter::charge_t BatteryMeter::state() const
{
    return m_state;
}
